package io.netty.example.study.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.epoll.EpollChannelOption;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.epoll.EpollSocketChannel;
import io.netty.example.study.server.codec.OrderFrameDecoder;
import io.netty.example.study.server.codec.OrderFrameEncoder;
import io.netty.example.study.server.codec.OrderProtocolDecoder;
import io.netty.example.study.server.codec.OrderProtocolEncoder;
import io.netty.example.study.server.codec.handler.AuthHandler;
import io.netty.example.study.server.codec.handler.MetricHandler;
import io.netty.example.study.server.codec.handler.OrderServerProcessHandler;
import io.netty.example.study.server.codec.handler.ServerIdleCheckHandler;
import io.netty.handler.flush.FlushConsolidationHandler;
import io.netty.handler.ipfilter.IpFilterRuleType;
import io.netty.handler.ipfilter.IpSubnetFilterRule;
import io.netty.handler.ipfilter.RuleBasedIpFilter;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.traffic.GlobalTrafficShapingHandler;
import io.netty.util.concurrent.DefaultThreadFactory;
import io.netty.util.concurrent.UnorderedThreadPoolEventExecutor;

import java.util.concurrent.ExecutionException;

public class Server {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.handler(new LoggingHandler(LogLevel.INFO));
        serverBootstrap.channel(EpollServerSocketChannel.class);

        // 通过线程工厂指定线程的名字，便于诊断
        EpollEventLoopGroup boss = new EpollEventLoopGroup(0, new DefaultThreadFactory("boss"));
        EpollEventLoopGroup worker = new EpollEventLoopGroup(0, new DefaultThreadFactory("worker"));
        serverBootstrap.group(boss, worker);

        // Netty 核心参数设置示例：
        serverBootstrap.childOption(EpollChannelOption.TCP_NODELAY, true); // 启用 Nagle 算法
        serverBootstrap.option(EpollChannelOption.SO_BACKLOG, 1028); // 调整最大等待连接数量

        // 用于支撑 IO 型 handler 的线程池
        final UnorderedThreadPoolEventExecutor executors
                = new UnorderedThreadPoolEventExecutor(10, new DefaultThreadFactory("business"));

        // 用于统计连接数量的 Handler，是多个子 Channel 共享的
        final MetricHandler metricHandler = new MetricHandler();

        // Netty 提供的用于流量整形的 Handler
        final GlobalTrafficShapingHandler globalTrafficShapingHandler
                // 这里需要的 Executor 比较轻量级，只是服务于 TrafficCounter，可以直接复用上面的 executors，也可以直接 new 出来；
                // 读写控制都定成 100M
                = new GlobalTrafficShapingHandler(new EpollEventLoopGroup(), 100 * 1024 * 1024, 100 * 1024 * 1024);

        // IpSubnetFilterRule 规则判断的是 Client 的 IP 和规则中的 IP 是否在同一个局域网中，规则定义如下：
        // 如果和规则定义的 IP 在同一个局域网中，就断开连接；
        // 如果和规则定义的 IP 不在同一个局域网中，就放过，什么都不做（127.0.0.1 和 192.168.31.100/8 不在一个局域网中，放过）；
        // 这个规则其实就是个黑名单
        final IpSubnetFilterRule ipSubnetFilterRule
                = new IpSubnetFilterRule("192.168.31.100", 8, IpFilterRuleType.REJECT);
        final RuleBasedIpFilter ruleBasedIpFilter = new RuleBasedIpFilter(ipSubnetFilterRule);

        // 自定义授权 handler
        final AuthHandler authHandler = new AuthHandler();

        serverBootstrap.childHandler(new ChannelInitializer<EpollSocketChannel>() {
            @Override
            protected void initChannel(EpollSocketChannel ch) throws Exception {
                // 需要注意顺序
                ChannelPipeline pipeline = ch.pipeline();

                // 这个日志 handler 用于打印解码前的字节信息，调试用的；
                pipeline.addLast(new LoggingHandler(LogLevel.DEBUG));

                // 黑名单 handler
                pipeline.addLast("ipFilter", ruleBasedIpFilter);

                // 流量整形的 Handler 要放到靠前一点的位置
                pipeline.addLast("TShandler", globalTrafficShapingHandler);

                // 用于空闲监测的 Handler
                pipeline.addLast("idleCheck", new ServerIdleCheckHandler());

                // 给 Handler 起个名字，方便调试
                pipeline.addLast("frameDecoder", new OrderFrameDecoder());
                pipeline.addLast(new OrderFrameEncoder());
                pipeline.addLast(new OrderProtocolEncoder());
                pipeline.addLast(new OrderProtocolDecoder());

                // 安装诊断应用程序运行信息的 handler
                pipeline.addLast("metricHandler", metricHandler);

                // 安装授权 handler，需要在二次 decoder 之后；
                pipeline.addLast("authHandler", authHandler);

                pipeline.addLast(new LoggingHandler(LogLevel.INFO));

                // 对 ctx.writeAndFlush(Object msg) 的优化的 Handler
                pipeline.addLast("flushEnhance",
                        // explicitFlushAfterFlushes：把 5 个 flush 攒到一起 flush；
                        // consolidateWhenNoReadInProgress：异步也增强；
                        new FlushConsolidationHandler(5, true));

                // 对于 IO 型的 handler，丢进线程池中执行，避免阻塞 EventLoopGroup 中的线程；
                pipeline.addLast(executors, new OrderServerProcessHandler());
            }
        });

        ChannelFuture channelFuture = serverBootstrap.bind(8090).sync();
        channelFuture.channel().closeFuture().get();

    }

}
